home *** CD-ROM | disk | FTP | other *** search
/ Suzy B Software 2 / Suzy B Software CD-ROM 2 (1994).iso / new_file / mintprgs / mint112s / mint112s.lzh / memprot.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-30  |  32.5 KB  |  1,194 lines

  1. /*
  2.  * Copyright 1991,1992,1993,1994 Atari Corporation.
  3.  * All rights reserved.
  4.  */
  5.  
  6. /*
  7.  * page-table data structures
  8.  *
  9.  *
  10.  * The root pointer points to a list of pointers to top-level pointer tables.
  11.  * 
  12.  * Each entry in a pointer table points to another pointer table or to
  13.  * a page table, or is a page descriptor.
  14.  * 
  15.  * Since, initially, the logical address space is the physical address space,
  16.  * we only need to worry about 26MB plus 32K for I/O space.
  17.  * 
  18.  * Since we want some pages to be supervisor-accessible, but we don't want
  19.  * a whole separate table for that, we use long-format descriptors.
  20.  * 
  21.  * Initial memory map:
  22.  * 
  23.  * 0     - membot: S (supervisor only)
  24.  * membot     - memtop: P (protected TPA)
  25.  * memtop     - phystop: G (screen)
  26.  * phystop     - $00E00000: bus error
  27.  * $00E00000- $00E3FFFF: G (ROM)
  28.  * $00E40000- $00FF7FFF: bus error
  29.  * $00FF8000- $00FFFFFF: G (mostly S: I/O space, but that's done in hardware)
  30.  * $01000000- ramtop: P
  31.  * ramtop     - $7FFFFFFF: G (A32/D32 VME, cacheable)
  32.  * $80000000- $FEFFFFFF: G (A32/D32 VME, non cacheable)
  33.  * $FFxxxxxx          just like $00xxxxxx.
  34.  * 
  35.  * Here's a final choice of layouts: IS=0, PS=13 (8K), TIA=4, TIB=4, TIC=4,
  36.  * TID=7.  This lets us map out entire unused megabytes at level C, and gives
  37.  * us an 8K page size, which is the largest the '040 can deal with.
  38.  * 
  39.  * This code implements 4+4+4+7, as follows:
  40.  * 
  41.  * tbl_a
  42.  *     0 -> tbl_b0
  43.  *     1-7 -> Cacheable direct (VME) page descriptors
  44.  *     8-E -> Non-cacheable direct (VME) page descriptors
  45.  *     F -> tbl_bf
  46.  * 
  47.  * tbl_b0 table: 16 entries (assumes only 16MB of TT RAM)
  48.  *     0 -> tbl_c00 (16MB of ST RAM address space)
  49.  *     1 -> tbl_c01 (16MB of TT RAM address space)
  50.  *     2-F -> cacheable direct (VME) page descriptors
  51.  * 
  52.  * tbl_bF table: 16 entries (deals with $FF mapping to $00)
  53.  *     0-E -> Non-cacheable direct (VME) page descriptors
  54.  *     F -> tbl_c00 (16MB of ST RAM address space, repeated here as $FF)
  55.  * 
  56.  * tbl_c00 table: ST RAM address space (example assuming 4MB ST RAM)
  57.  *     0-3 -> RAM page tables
  58.  *     4-D -> invalid
  59.  *     E -> direct map, cache enable (ROM)
  60.  *     F -> direct map, cache inhibit (I/O)
  61.  * 
  62.  * For each 16MB containing any TT RAM, there's a tbl_c.  Within those,
  63.  * for each MB that actually has TT RAM, there's another table, containing
  64.  * 128 RAM page tables.  Where there isn't RAM, there are "global"
  65.  * pages, to let the hardware bus error or not as it sees fit.
  66.  * 
  67.  * One RAM page table is allocated per megabyte of real RAM; each table has
  68.  * 128 entries, which is 8K per page.  For a TT with 4MB ST RAM and 4MB TT RAM
  69.  * that's 8K in page tables.  You can cut this down by not allocating page
  70.  * tables for which the entire megabyte is not accessible (i.e. it's all
  71.  * private memory and it's not YOUR private memory).
  72.  * 
  73.  * You have one of these per process.  When somebody loads into G or S memory
  74.  * or leaves it, you have to go through the page tables of every process
  75.  * updating S bits (for S) and DT (for G) bits.
  76.  * 
  77.  * The top levels are small & easy so replicating them once per process
  78.  * doesn't really hurt us.
  79.  * 
  80.  */
  81.  
  82. #include "mint.h"
  83.  
  84. #if 0
  85. #define MP_DEBUG(x) DEBUG(x)
  86. #else
  87. #define MP_DEBUG(x)
  88. #endif
  89.  
  90. void *memset P_((void *s, int ucharfill, unsigned long size));
  91. static void _dump_tree P_((long_desc tbl, int level));
  92.  
  93. extern int debug_level;        /* see debug.c */
  94. extern long mcpu;        /* in main.c */
  95.  
  96. /*
  97.  * You can turn this whole module off, and the stuff in context.s,
  98.  * by setting no_mem_prot to 1.
  99.  */
  100.  
  101. int no_mem_prot;
  102. long page_table_size;
  103.  
  104. /*
  105.  * PMMU stuff
  106.  */
  107.  
  108. /*
  109.  * This is one global TC register that is copied into every process'
  110.  * context, even though it never changes.  It's also used by the
  111.  * functions that dump page tables.
  112.  */
  113.  
  114. tc_reg tc;
  115.  
  116. /* mint_top_* get used in mem.c also */
  117. ulong mint_top_tt;
  118. ulong mint_top_st;
  119.  
  120. int tt_mbytes;        /* number of megabytds of TT RAM */
  121.  
  122. /*
  123.  * global_mode_table: one byte per page in the system.  Initially all pages
  124.  * are set to "global" but then the TPA pages are set to "invalid" in
  125.  * init_mem.  This has to be allocated and initialized in init_tables,
  126.  * when you know how much memory there is.  You need a byte per page,
  127.  * from zero to the end of TT RAM, including the space between STRAM
  128.  * and TTRAM.  That is, you need 16MB/pagesize plus (tt_mbytes/pagesize)
  129.  * bytes here.
  130.  */
  131.  
  132. unsigned char *global_mode_table;
  133.  
  134. /*
  135.  * prototype descriptors; field u1 must be all ones, other u? are zero.
  136.  * This is just the first long of a full descriptor; the ".page_type" part
  137.  * of the union.  These are initialized by init_tables.
  138.  *
  139.  * The proto_page_type table yields the value to stuff into the page_type
  140.  * field of a new process' page table.  It is the "non-owner" mode for
  141.  * a page with the corresponding value in global_mode_table.
  142.  */
  143.  
  144. page_type g_page;
  145. page_type g_ci_page;
  146. page_type s_page;
  147. page_type readable_page;
  148. page_type invalid_page;
  149. page_type page_ptr;
  150.  
  151. page_type *const proto_page_type[] =
  152.     { &invalid_page, &g_page, &s_page, &readable_page, &invalid_page };
  153. /*    private         global    super    private/read    invalid */
  154.  
  155. /*
  156.  * Init_tables: called sometime in initialization.  We set up some
  157.  * constants here, but that's all.  The first new_proc call will set up the
  158.  * page table for the root process and switch it in; from then on, we're
  159.  * always under some process' control.
  160.  * 
  161.  * The master page-mode table is initialized here, and some constants like
  162.  * the size needed for future page tables.
  163.  *
  164.  * One important constant initialized here is page_table_size, which is
  165.  * the amount of memory required per page table.  new_proc allocates
  166.  * this much memory for each process' page table.  This number will be
  167.  * 1K/megabyte plus page table overhead.  There are TBL_PAGES_OFFS
  168.  * tables at TBL_SIZE_BYTES each before the main tables begin; then
  169.  * there is 1024 bytes per megabyte of memory being mapped.
  170.  */
  171.  
  172. void
  173. init_tables()
  174. {
  175.     int n_megabytes;
  176.     long global_mode_table_size;
  177.  
  178.     if (no_mem_prot) return;
  179.  
  180.     TRACE(("init_tables"));
  181.  
  182. #define phys_top_tt (*(ulong *)0x5a4L)
  183.     if (phys_top_tt == 0x01000000L) mint_top_tt = 0;
  184.     else mint_top_tt = phys_top_tt;
  185.  
  186. #define phys_top_st (*(ulong *)0x42eL)
  187.     mint_top_st = phys_top_st;
  188.  
  189.     if (mint_top_tt)
  190.         tt_mbytes = (int) ((mint_top_tt - 0x01000000L) / ONE_MEG);
  191.     else
  192.         tt_mbytes = 0;
  193.  
  194.     n_megabytes = (int) ((mint_top_st / ONE_MEG) + tt_mbytes);
  195.  
  196.     /*
  197.      * page table size: room for A table, B0 table, BF table, STRAM C
  198.      * table, one TTRAM C table per 16MB (or fraction) of TTRAM, and 1024
  199.      * bytes per megabyte.
  200.      */
  201.  
  202.     page_table_size = (4L * TBL_SIZE_BYTES) +
  203.               (((tt_mbytes+15L)/16L) * TBL_SIZE_BYTES) +
  204.               (n_megabytes*1024L);
  205.  
  206.     global_mode_table_size = ((SIXTEEN_MEG / QUANTUM) +
  207.                 (((ulong)tt_mbytes * ONE_MEG) / QUANTUM));
  208.  
  209.     global_mode_table = kmalloc(global_mode_table_size);
  210.  
  211.     assert(global_mode_table);
  212.  
  213.     TRACELOW(("mint_top_st is $%lx; mint_top_tt is $%lx, n_megabytes is %d",
  214.     mint_top_st, mint_top_tt, n_megabytes));
  215.     TRACELOW(("page_table_size is %ld, global_mode_table_size %ld",
  216.         page_table_size,
  217.         global_mode_table_size));
  218.  
  219.     g_page.limit = 0x7fff;    /* set nonzero fields: disabled limit */
  220.     g_page.unused1 = 0x3f;    /* ones in this reserved field */
  221.     g_page.unused2 = 0;
  222.     g_page.s = 0;
  223.     g_page.unused3 = 0;
  224.     g_page.ci = 0;
  225.     g_page.unused4 = 0;
  226.     g_page.m = 1;        /* set m and u to 1 so CPU won't do writes */
  227.     g_page.u = 1;
  228.     g_page.wp = 0;        /* not write-protected */
  229.     g_page.dt = 1;        /* descriptor type 1: page descriptor */
  230.  
  231.     g_ci_page = g_page;
  232.     g_ci_page.ci = 1;
  233.  
  234.     readable_page = g_page;    /* a page which is globally readable */
  235.     readable_page.wp = 1;    /* but write protected */
  236.  
  237.     s_page = g_page;        /* a page which is globally accessible */
  238.     s_page.s = 1;        /* if you're supervisor */
  239.  
  240.     invalid_page = g_page;
  241.     invalid_page.dt = 0;
  242.  
  243.     page_ptr = g_page;
  244.     page_ptr.m = 0;        /* this must be zero in page pointers */
  245.     page_ptr.dt = 3;
  246.  
  247.     tc.enable = 1;
  248.     tc.zeros = 0;
  249.     tc.sre = 0;
  250.     tc.fcl = 0;
  251.     tc.is = 0;
  252.     tc.tia = 4;
  253.     tc.tib = 4;
  254.     tc.tic = 4;
  255.     tc.tid = 7;            /* 0+4+4+4+7+13 == 32 */
  256.     tc.ps = 13;            /* 8K page size */
  257.  
  258.     /* set the whole global_mode_table to "global" */
  259.     memset(global_mode_table,PROT_G,global_mode_table_size);
  260. }
  261.  
  262. /*
  263.  * mark_region: mark a region of memory as having a particular type.
  264.  * The arguments are the memory region in question and the new type.
  265.  * If the new type is zero then the old type is preserved.  The
  266.  * type of each page is kept in a global place for this purpose,
  267.  * among others.
  268.  *
  269.  * The types are:
  270.  *  0    private
  271.  *  1    global
  272.  *  2    private, but super-accessible
  273.  *  3    private, but world readable
  274.  *  4   invalid
  275.  *
  276.  
  277. The idea is this:
  278.  
  279.     for (each process) {
  280.     if (you're an owner or you're special) {
  281.         set up owner modes
  282.     }
  283.     else {
  284.         set up non-owner modes
  285.     }
  286.  
  287.     mark_pages(pagetbl,start,len,modes);
  288.     }
  289.  
  290.  */
  291.  
  292. /*
  293.                 invalid---v
  294.               private/gr---v  |
  295.                 super-------v  |  |
  296.             global-------v  |  |  |
  297.         private-------v     |  |  |  |
  298.                   |     |  |  |  |
  299. */
  300. const ushort other_dt[]    =   { 0, 1, 1, 1, 0 };
  301. const ushort other_s[] =    { 0, 0, 1, 0, 0 };
  302. const ushort other_wp[] =   { 0, 0, 0, 1, 0 };
  303.  
  304.  
  305. /*
  306.  * get_page_cookie: return a cookie representing the protection status
  307.  * of some memory.
  308.  *
  309.  * Returns ((wp << 3) | (s << 2) | (dt) | 0x8000) when it wins.
  310.  * Returns 1 if the pages are not all controlled, 0 if they're not all the same.
  311.  */
  312.  
  313. static short
  314. get_page_cookie(long_desc *base_tbl,ulong start,ulong len)
  315. {
  316.     int b_index, c_index, d_index;
  317.     long_desc *tbl, *tbl_b, *tbl_c;
  318.     int dt, s, wp;
  319.  
  320.     if (start < mint_top_st) {
  321.     /* start is in ST RAM; fail if not entirely in ST RAM */
  322.     if (start+len > mint_top_st) {
  323.         return 1;
  324.     }
  325.     }
  326.     else if (start >= 0x01000000L && start < mint_top_tt) {
  327.     /* start is in TT RAM; fail if not entirely in TT RAM */
  328.     if (start+len > mint_top_tt) {
  329.         return 1;
  330.     }
  331.     }
  332.  
  333.     /*
  334.      * a_index is always zero.  Only the first 256MB is mapped.
  335.      * b_index is the 16MB number of the page.
  336.      * c_index is the 1MB number of that page within the 16MB (0-15)
  337.      * d_index is the 8K number within that 1MB (0-127).
  338.      */
  339.  
  340.     b_index = (int)(start >> LOG2_16_MEG);
  341.     c_index = (int)(start >> LOG2_ONE_MEG) & 0xf;
  342.     d_index = (int)(start >> LOG2_EIGHT_K) & 0x7f;
  343.  
  344.     /* precompute the table addresses */
  345.     tbl_b = &base_tbl[0].tbl_address[b_index];
  346.     tbl_c = &tbl_b->tbl_address[c_index];
  347.     tbl = &tbl_c->tbl_address[d_index];
  348.  
  349.     dt = tbl->page_type.dt;
  350.     wp = tbl->page_type.wp;
  351.     s = tbl->page_type.s;
  352.  
  353.     for (;;) {
  354.     /* quickly loop through the 1MB-block */
  355.     for (; len && tbl < &tbl_c->tbl_address[0x80]; tbl++)
  356.       {
  357.         if ((tbl->page_type.dt != dt) ||
  358.         (tbl->page_type.s != s) ||
  359.         (tbl->page_type.wp != wp)) {
  360.             /* fail because it's not all the same protection */
  361.             return 0;
  362.         }
  363.         len -= EIGHT_K;
  364.       }
  365.  
  366.     if (len == 0L)
  367.       break;
  368.  
  369.     /* step to the next d-table */
  370.     tbl_c++;
  371.     /* if crossing a 16MB boundary, get the next c-table */
  372.     if (tbl_c == &tbl_b->tbl_address[0x10])
  373.       {
  374.         tbl_b++;
  375.         tbl_c = tbl_b->tbl_address;
  376.       }
  377.     tbl = tbl_c->tbl_address;
  378.     }
  379.     /* we passed -- all the pages in question have the same prot. status */
  380.     return (wp << 3) | (s << 2) | dt | 0x8000;
  381. }
  382.  
  383. static void
  384. mark_pages(long_desc *base_tbl,ulong start,ulong len,
  385.         ushort dt_val, ushort s_val, ushort wp_val, PROC *proc)
  386. {
  387.     int b_index, c_index, d_index;
  388.     long_desc *tbl, *tbl_b, *tbl_c;
  389.     ulong oldlen;
  390.  
  391.     UNUSED(proc);
  392.  
  393.     if (no_mem_prot) return;
  394.  
  395.     oldlen = len;
  396.  
  397.     /*
  398.      * a_index is always zero.  Only the first 256MB is mapped.
  399.      * b_index is the 16MB number of the page.
  400.      * c_index is the 1MB number of that page within the 16MB (0-15)
  401.      * d_index is the 8K number within that 1MB (0-127).
  402.      */
  403.  
  404.     b_index = (int)(start >> LOG2_16_MEG);
  405.     c_index = (int)(start >> LOG2_ONE_MEG) & 0xf;
  406.     d_index = (int)(start >> LOG2_EIGHT_K) & 0x7f;
  407.  
  408.     /* precompute the table addresses */
  409.     tbl_b = &base_tbl[0].tbl_address[b_index];
  410.     tbl_c = &tbl_b->tbl_address[c_index];
  411.     tbl = &tbl_c->tbl_address[d_index];
  412.  
  413. #ifdef MEMPROT_SHORTCUT
  414.     /*
  415.      * Take a shortcut here: we're done if first page of the region is
  416.      * already right.
  417.      */
  418.     /* I don't think this shortcut is a good idea, since while we
  419.      * are doing Mshrink or Srealloc we may very well have a region
  420.      * with mixed page types -- ERS
  421.      */
  422.  
  423.     if (tbl->page_type.dt == dt_val &&
  424.     tbl->page_type.s == s_val &&
  425.     tbl->page_type.wp == wp_val) {
  426. /*
  427.         TRACE(("mark_pages a:0 b:%d c:%d d:%d (same)",
  428.             b_index,c_index,d_index));
  429. */
  430.         return;
  431.     }
  432.  
  433. #endif /* MEMPROT_SHORTCUT */
  434. /*
  435.     MP_DEBUG(("mark_pages a:0 b:%d c:%d d:%d (diff)",b_index,c_index,d_index));
  436. */
  437.  
  438.     for (;;)
  439.       {
  440.     /* quickly loop through the 1MB-block */
  441.     for (; len && tbl < &tbl_c->tbl_address[0x80]; tbl++)
  442.       {
  443.         tbl->page_type.dt = dt_val;
  444.         tbl->page_type.s = s_val;
  445.         tbl->page_type.wp = wp_val;
  446.         len -= EIGHT_K;
  447.       }
  448.  
  449.     if (len == 0L)
  450.       break;
  451.  
  452.     /* get the next d-table */
  453.     tbl_c++;
  454.     /* if crossing a 16MB boundary, get the next c-table */
  455.     if (tbl_c == &tbl_b->tbl_address[0x10])
  456.       {
  457.         tbl_b++;
  458.         tbl_c = tbl_b->tbl_address;
  459.       }
  460.     tbl = tbl_c->tbl_address;
  461.     }
  462.  
  463.     flush_pmmu();
  464.     if (mcpu <= 30) {
  465.     /* On the '020 & '030 we have a logical cache, i.e. the DC & IC are on
  466.      * the CPU side of the MMU, hence on an MMU context switch we must flush
  467.      * them too. On the '040, by comparison, we have a physical cache, i.e.
  468.      * the DC & IC are on the memory side of the MMU, so no DC/IC cache flush
  469.      * is needed.
  470.      */
  471.     cpush((void *)start, oldlen);
  472.     }
  473. }
  474.  
  475. /* get_prot_mode(r): returns the type of protection region r
  476.  * has
  477.  */
  478.  
  479. int
  480. get_prot_mode(r)
  481.     MEMREGION *r;
  482. {
  483.     ulong start = r->loc;
  484.  
  485.     if (no_mem_prot)
  486.         return PROT_G;
  487.     return global_mode_table[(start >> 13)];
  488. }
  489.  
  490. void
  491. mark_region(region,mode)
  492. MEMREGION *region;
  493. short mode;
  494. {
  495.     ulong start = region->loc;
  496.     ulong len = region->len;
  497.     ulong i;
  498.     ushort dt_val, s_val, wp_val;
  499.     PROC *proc;
  500.     MEMREGION **mr;
  501.  
  502.     if (no_mem_prot) return;
  503.  
  504.     MP_DEBUG(("mark_region %lx len %lx mode %d",start,len,mode));
  505.     
  506. #if 0 /* this should not occur any more */
  507.     if (mode == PROT_NOCHANGE) {
  508.     mode = global_mode_table[(start >> 13)];
  509.     }
  510. #else
  511.     assert(mode != PROT_NOCHANGE);
  512. #endif
  513.  
  514.     /* mark the global page table */
  515.  
  516.     memset(&global_mode_table[start >> 13],mode,(len >> 13));
  517.  
  518.     for (proc = proclist; proc; proc = proc->gl_next) {
  519.     assert(proc->page_table);
  520.     if (mode == PROT_I || mode == PROT_G) {
  521.         /* everybody gets the same flags */
  522.         goto notowner;
  523.     }
  524.     if (proc->memflags & F_OS_SPECIAL) {
  525.         /* you're special; you get owner flags */
  526.         MP_DEBUG(("mark_region: pid %d is an OS special!",proc->pid));
  527.         goto owner;
  528.     }
  529.     if ((mr = proc->mem) != 0) {
  530.         for (i = 0; i < proc->num_reg; i++, mr++) {
  531.         if (*mr == region) {
  532.             MP_DEBUG(("mark_region: pid %d is an owner",proc->pid));
  533. owner:
  534.             dt_val = 1;
  535.             s_val = 0;
  536.             wp_val = 0;
  537.             goto gotvals;
  538.         }
  539.         }
  540.     }
  541.  
  542. notowner:
  543.  
  544. /* if you get here you're not an owner, or mode is G or I */
  545.     MP_DEBUG(("mark_region: pid %d gets non-owner modes",proc->pid));
  546.  
  547.     dt_val = other_dt[mode];
  548.     s_val = other_s[mode];
  549.     wp_val = other_wp[mode];
  550.  
  551. gotvals:
  552.     mark_pages(proc->page_table,start,len,dt_val,s_val,wp_val,proc);
  553.     }
  554. }
  555.  
  556. /* special version of mark_region, used for attaching (mode == PROT_P)
  557.    and detaching (mode == PROT_I) a memory region to/from a process. */
  558. void
  559. mark_proc_region(proc,region,mode)
  560. PROC *proc;
  561. MEMREGION *region;
  562. short mode;
  563. {
  564.     ulong start = region->loc;
  565.     ulong len = region->len;
  566.     ushort dt_val, s_val, wp_val;
  567.     short global_mode;
  568.  
  569.     if (no_mem_prot) return;
  570.  
  571.     MP_DEBUG(("mark_region %lx len %lx mode %d for pid %d",
  572.           start, len, mode, proc->pid));
  573.  
  574.     global_mode = global_mode_table[(start >> 13)];
  575.  
  576.     assert(proc->page_table);
  577.     if (global_mode == PROT_I || global_mode == PROT_G)
  578.       mode = global_mode;
  579.     else {
  580.     if (proc->memflags & F_OS_SPECIAL) {
  581.         /* you're special; you get owner flags */
  582.         MP_DEBUG(("mark_region: pid %d is an OS special!",proc->pid));
  583.         goto owner;
  584.     }
  585.     if (mode == PROT_P) {
  586.         MP_DEBUG(("mark_region: pid %d is an owner",proc->pid));
  587. owner:
  588.         dt_val = 1;
  589.         s_val = 0;
  590.         wp_val = 0;
  591.         goto gotvals;
  592.     }
  593.     }
  594.  
  595. /* if you get here you're not an owner, or mode is G or I */
  596.     MP_DEBUG(("mark_region: pid %d gets non-owner modes",proc->pid));
  597.  
  598.     dt_val = other_dt[mode];
  599.     s_val = other_s[mode];
  600.     wp_val = other_wp[mode];
  601.  
  602. gotvals:
  603.     mark_pages(proc->page_table,start,len,dt_val,s_val,wp_val,proc);
  604. }
  605.  
  606. /*
  607.  * prot_temp: temporarily alter curproc's access to memory.
  608.  * Pass in a -1 to give curproc global access; returns a cookie.  Call
  609.  * again with that cookie to return the memory to the old mode.
  610.  * There should be no context switches or memory protection changes
  611.  * in the meantime.
  612.  *
  613.  * If called with mode == -1, returns...
  614.  *    -1 if mem prot is off -- no error, no action.
  615.  *     0 if the pages are not all the same.
  616.  *     1 if the pages are not all controlled by the page tables.
  617.  *
  618.  * When mode != -1, returns...
  619.  *    0 for success (should never fail).  There is little checking.
  620.  * Calling with mode == 0 or 1 results in zero to spoof success, but in fact
  621.  * this is an error.  Mode is only really valid if (mode & 0x8000).
  622.  */
  623.  
  624. int
  625. prot_temp(loc,len,mode)
  626. ulong loc;
  627. ulong len;
  628. int mode;
  629. {
  630.     int cookie;
  631.  
  632.     if (no_mem_prot) return -1;
  633.  
  634.     /* round start down to the previous page and len up to the next one. */
  635.     len += loc & MASKBITS;
  636.     loc &= ~MASKBITS;
  637.     len = ROUND(len);
  638.  
  639.     if (mode == 0 || mode == 1) return 0;    /* do nothing */
  640.     if (mode == -1) {
  641.     cookie = get_page_cookie(curproc->page_table,loc,len);
  642.  
  643.     /* if not all controlled, return status */
  644.     if (cookie == 0 || cookie == 1) return cookie;
  645.  
  646.     mark_pages(curproc->page_table,loc,len,1,0,0,curproc);
  647.  
  648.     return cookie;
  649.     }
  650.     else {
  651.     mark_pages(curproc->page_table,loc,len,
  652.             mode&3,(mode&4)>>2,(mode&8)>>3,curproc);
  653.     return 0;
  654.     }
  655. }
  656.  
  657. /*
  658.  * init_page_table: fill in the page table for the indicated process. The
  659.  * master page map is consulted for the modes of all pages, and the memory
  660.  * region data structures are consulted to see if this process is the owner
  661.  * of any of those tables.
  662.  *
  663.  * This also sets crp and tc in both ctxts of the process.  If this is the
  664.  * first call, then the CPU tc is cleared, the TT0 and TT1 regs are zapped,
  665.  * and then this proc's crp and tc are loaded into it.
  666.  */
  667.  
  668. static short mmu_is_set_up = 0;
  669.  
  670. void
  671. init_page_table(proc)
  672. PROC *proc;
  673. {
  674.     long_desc *tptr;
  675.     long_desc *tbl_a;        /* top-level table */
  676.     long_desc *tbl_b0;        /* second level, handles $0 nybble */
  677.     long_desc *tbl_bf;        /* handles $F nybble */
  678.     long_desc *tbl_c;        /* temp pointer to start of 16MB */
  679.     ulong p, q, r;
  680.     ulong i, j, k;
  681.     int g;
  682.     MEMREGION **mr;
  683.  
  684.     if (no_mem_prot) return;
  685.  
  686.     assert(proc && proc->page_table);
  687.  
  688.     if (proc->pid)
  689.         TRACELOW(("init_page_table(proc=%lx, pid %d)",proc,proc->pid));
  690.  
  691.     tptr = proc->page_table;
  692.     tbl_a = tptr;
  693.     tptr += TBL_SIZE;
  694.     tbl_b0 = tptr;
  695.     tptr += TBL_SIZE;
  696.     tbl_bf = tptr;
  697.     tptr += TBL_SIZE;
  698.  
  699.     /*
  700.      * table A indexes by the first nybble: $0 and $F refer to their tables,
  701.      * $1-$7 are uncontrolled, cacheable; $8-$E are uncontrolled, ci.
  702.      */
  703.  
  704.     tbl_a[0].page_type = page_ptr;
  705.     tbl_a[0].tbl_address = tbl_b0;
  706.  
  707.     for (i=1; i<0xf; i++) {
  708.     if (i < 8)  tbl_a[i].page_type = g_page;
  709.     else        tbl_a[i].page_type = g_ci_page;
  710.     tbl_a[i].tbl_address = (long_desc *)(i << 28);
  711.     }
  712.  
  713.     /* $F entry of table A refers to table BF */
  714.     tbl_a[0xf].page_type = page_ptr;
  715.     tbl_a[0xf].tbl_address = tbl_bf;
  716.  
  717.     /*
  718.      * table B0: entry 0 is $00, the 16MB of ST address space.
  719.      */
  720.  
  721.     tbl_b0[0].page_type = page_ptr;
  722.     tbl_b0[0].tbl_address = tptr;
  723.     tbl_c = tptr;
  724.     tptr += TBL_SIZE;
  725.  
  726.     /* for each megabyte that is RAM, allocate a table */
  727.     for (i = 0, k = 0, p = 0; p < mint_top_st; i++, p += 0x00100000L) {
  728.     tbl_c[i].page_type = page_ptr;
  729.     tbl_c[i].tbl_address = tptr;
  730.  
  731.     /* for each page in this megabyte, write a page entry */
  732.     for (q = p, j = 0; j < 128; j++, q += 0x2000, k++) {
  733.         tptr->page_type = *proto_page_type[global_mode_table[k]];
  734.         tptr->tbl_address = (long_desc *)q;
  735.         tptr++;
  736.     }
  737.     }
  738.  
  739.     /* now for each megabyte from mint_top_st to ROM, mark global */
  740.     for ( ; p < 0x00E00000L; i++, p += 0x00100000L) {
  741.     tbl_c[i].page_type = g_page;
  742.     tbl_c[i].tbl_address = (long_desc *)p;
  743.     }
  744.  
  745.     /* fill in the E and F tables: 00Ex is ROM, 00Fx is I/O  */
  746.     tbl_c[i].page_type = g_page;
  747.     tbl_c[i].tbl_address = (long_desc *)p;
  748.     i++, p += 0x00100000L;
  749.     tbl_c[i].page_type = g_ci_page;
  750.     tbl_c[i].tbl_address = (long_desc *)p;
  751.  
  752.         /* Done with tbl_c for 0th 16MB; go on to TT RAM */
  753.  
  754. /* 
  755.     structure:
  756.  
  757.     for (i = each 16MB that has any TT RAM in it)
  758.     allocate a table tbl_c, point tbl_b0[i] at it
  759.     for (j = each 1MB that is RAM)
  760.         allocate a table, point tbl_c[j] at it
  761.         for (k = each page in the megabyte)
  762.         fill in tbl_c[j][k] with page entry from global_mode_table
  763.     for (j = the rest of the 16MB)
  764.         set tbl_c[j] to "global, cacheable"
  765.  
  766.     for (i = the rest of the 16MBs from here to $7F)
  767.     set tbl_b0[i] to "global, cacheable"
  768.  
  769.     for (i = the rest of the 16MBs from $80 up to but not incl. $FF)
  770.     set tbl_b0[i] to "global, not cacheable"
  771. */
  772.  
  773.     /* i counts 16MBs */
  774.     for (i = 1, p = 0x01000000L, g = 2048;
  775.      p < mint_top_tt;
  776.      p += SIXTEEN_MEG, i++) {
  777.         tbl_b0[i].page_type = page_ptr;
  778.         tbl_b0[i].tbl_address = tptr;
  779.         tbl_c = tptr;
  780.         tptr += TBL_SIZE;
  781.  
  782.         /* j counts MBs */
  783.         for (j = 0, q = p; j < 16 && q < mint_top_tt; q += ONE_MEG, j++) {
  784.         tbl_c[j].page_type = page_ptr;
  785.         tbl_c[j].tbl_address = tptr;
  786.         /* k counts pages (8K) */
  787.         for (r = q, k = 0; k < 128; k++, r += 0x2000, g++) {
  788.             tptr->page_type = *proto_page_type[global_mode_table[g]];
  789.             tptr->tbl_address = (long_desc *)r;
  790.             tptr++;
  791.         }
  792.         }
  793.         for ( ; j < 16; j++, q += ONE_MEG) {
  794.         /* fill in the rest of this 16MB */
  795.         tbl_c[j].page_type = g_page;
  796.         tbl_c[j].tbl_address = (long_desc *)q;
  797.         }
  798.     }
  799.  
  800.     /* fill in the rest of $00-$0F as cacheable */
  801.     for ( ; i < 16; i++, p += SIXTEEN_MEG) {
  802.     tbl_b0[i].page_type = g_page;
  803.     tbl_b0[i].tbl_address = (long_desc *)p;
  804.     }
  805.  
  806.     /* done with TT RAM in table b0; do table bf */
  807.  
  808.     /*
  809.      * Table BF: translates addresses starting with $F.  First 15 are
  810.      * uncontrolled, cacheable; last one translates $FF, which
  811.      * which shadows $00 (the 16MB ST address space).  The rest
  812.      * are uncontrolled, not cacheable.
  813.      *
  814.      * The table address of the copy has a 1 in the low (unused) bit, which
  815.      * is a signal to the table dumper not to dump this, as it's a copy
  816.      * of tbl_b0[0].
  817.      */
  818.  
  819.     for (i=0; i<0xf; i++) {
  820.     tbl_bf[i].page_type = g_ci_page;
  821.     tbl_bf[i].tbl_address = (long_desc *)((i << 24) | 0xf0000000L);
  822.     }
  823.     tbl_bf[0xf] = tbl_b0[0];
  824.     *(ulong *)(&(tbl_bf[0xf].tbl_address)) |= 1;
  825.  
  826.     proc->ctxt[0].crp.limit = 0x7fff;    /* disable limit function */
  827.     proc->ctxt[0].crp.dt = 3;        /* points to valid 8-byte entries */
  828.     proc->ctxt[0].crp.tbl_address = tbl_a;
  829.     proc->ctxt[1].crp = proc->ctxt[0].crp;
  830.     proc->ctxt[0].tc = tc;
  831.     proc->ctxt[1].tc = tc;
  832.  
  833.     /*
  834.      * OK, memory tables are now there as if you're a non-owner of every
  835.      * page.  Now for each region you ARE an owner of, mark with owner
  836.      * modes.
  837.      */
  838.  
  839.     mr = proc->mem;
  840.     for (i=0; i < proc->num_reg; i++, mr++) {
  841.     if (*mr) {
  842.             mark_pages(proc->page_table,(*mr)->loc,(*mr)->len,1,0,0,proc);
  843.         }
  844.     }
  845.  
  846.     if (!mmu_is_set_up) {
  847.     set_mmu(proc->ctxt[0].crp,proc->ctxt[0].tc);
  848.     mmu_is_set_up = 1;
  849.     }
  850. }
  851.  
  852. /*
  853.  * This routine is called when procfs detects that a process wants to be an
  854.  * OS SPECIAL.  The AES, SCRENMGR, and DESKTOP do this, and so does FSMGDOS
  855.  * and possibly some other stuff. It has to re-mark every page in that
  856.  * process' page table based on its new special status. The "special
  857.  * status" is "you get global access to all of memory" and "everybody
  858.  * gets Super access to yours."  It is the caller's responsibility
  859.  * to set proc's memflags, usually to (F_OS_SPECIAL | F_PROT_S).
  860.  */
  861.  
  862. void
  863. mem_prot_special(proc)
  864. PROC *proc;
  865. {
  866.     MEMREGION **mr;
  867.     int i;
  868.  
  869.     if (no_mem_prot) return;
  870.  
  871.     TRACE(("mem_prot_special(pid %d)",proc->pid));
  872.  
  873.     /*
  874.      * This marks ALL memory, allocated or not, as accessible. When memory
  875.      * is freed even F_OS_SPECIAL processes lose access to it. So one or
  876.      * the other of these is a bug, depending on how you want it to work.
  877.      */
  878.     mark_pages(proc->page_table,0,mint_top_st,1,0,0,proc);
  879.     if (mint_top_tt) {
  880.     mark_pages(proc->page_table,
  881.             0x01000000L,
  882.             mint_top_tt - 0x01000000L,
  883.             1,0,0,
  884.             proc);
  885.     }
  886.  
  887.     /*
  888.      * In addition, mark all the pages the process already owns as "super"
  889.      * in all other processes.  Thus the "special" process can access all
  890.      * of memory, and any process can access the "special" process' memory
  891.      * when in super mode.
  892.      */
  893.  
  894.     mr = proc->mem;
  895.  
  896.     for (i=0; i < proc->num_reg; i++, mr++) {
  897.     if (*mr) {
  898.         mark_region(*mr,PROT_S);
  899.     }
  900.     }
  901. }
  902.     
  903. /*----------------------------------------------------------------------------
  904.  * DEBUGGING SECTION
  905.  *--------------------------------------------------------------------------*/
  906.  
  907. static void
  908. _dump_tree(tbl,level)
  909. long_desc tbl;
  910. int level;
  911. {
  912.     int i, j;
  913.     long_desc *p;
  914.     static const char spaces[9] = "        ";
  915.  
  916.     /* print the level and display the table descriptor */
  917.     FORCE("\r%s s:%x wp:%x dt:%x a:%08lx",
  918.     &spaces[8-(level*2)],
  919.     tbl.page_type.s,
  920.     tbl.page_type.wp,
  921.     tbl.page_type.dt,
  922.     tbl.tbl_address);
  923.  
  924.     if (tbl.page_type.dt == 3) {
  925.     if (level == 0) {
  926.         j = (1 << tc.tia);
  927.     }
  928.     else if (level == 1) {
  929.         j = (1 << tc.tib);
  930.     }
  931.     else if (level == 2) {
  932.         j = (1 << tc.tic);
  933.     }
  934.     else {
  935.         j = (1 << tc.tid);
  936.     }
  937.  
  938.     /* don't show table if it's the duplicate */
  939.     if ((ulong)tbl.tbl_address & 1) return;
  940.  
  941.     ++level;
  942.     p = tbl.tbl_address;
  943.     for (i=0; i<j; i++, p++) {
  944.         _dump_tree(*p,level);
  945.     }
  946.     }
  947. }
  948.  
  949. static const char modesym[] = { 'p', 'g', 's', 'r', 'i' };
  950.  
  951. void
  952. QUICKDUMP()
  953. {
  954.     char outstr[33];
  955.     ulong i, j, end;
  956.  
  957.     if (no_mem_prot) return;
  958.  
  959.     FORCE("STRAM global table:");
  960.     outstr[32] = '\0';
  961.     end = mint_top_st / QUANTUM;
  962.     for (i = 0; i < end; i += 32) {
  963.     for (j=0; j<32; j++) {
  964.         outstr[j] = modesym[global_mode_table[j+i]];
  965.     }
  966.     FORCE("%08lx: %s",i*8192L,outstr);
  967.     }
  968.  
  969.     if (mint_top_tt) {
  970.     FORCE("TTRAM global table:");
  971.     end = mint_top_tt / QUANTUM;
  972.     for (i = 2048; i < end; i += 32) {
  973.         for (j=0; j<32; j++) {
  974.         outstr[j] = modesym[global_mode_table[j+i]];
  975.         }
  976.         FORCE("%08lx: %s",i*8192L,outstr);
  977.     }
  978.     }
  979. }
  980.  
  981. const char *berr_msg[] = { 
  982. /*  "........." */
  983.     "private  ",
  984.     "global   ",    /* turned into "hardware" for violation reports */
  985.     "super    ",
  986.     "readable ",
  987.     "free     ",
  988.     "hardware "        /* used when the memory is not controlled by us */
  989. };
  990.  
  991. void
  992. report_buserr()
  993. {
  994.     const char *vmsg;
  995.     short mode;
  996.     ulong aa, pc;
  997.     char alertbuf[5*32+16];    /* enough for an alert */
  998.     char *aptr;
  999.  
  1000.     if (no_mem_prot) return;
  1001.  
  1002.     aa = curproc->exception_addr;
  1003.     pc = curproc->exception_pc;
  1004.     if ((mint_top_tt && aa < mint_top_tt) || (aa < mint_top_st)) {
  1005.     mode = global_mode_table[(curproc->exception_addr >> 13)];
  1006.     if (mode == PROT_G) {
  1007.         /* page is global: obviously a hardware bus error */
  1008.         mode = 5;
  1009.     }
  1010.     }
  1011.     else {
  1012.     /* (addr is > mint_top_tt) set mode = 5 so we don't look for owners */
  1013.         mode = 5;
  1014.     }
  1015.     vmsg = berr_msg[mode];
  1016.  
  1017.     /* construct an AES alert box for this error:
  1018.     | PROCESS  "buserrxx"  KILLED: |
  1019.     | MEMORY VIOLATION.  (PID 000) |
  1020.     |                              |
  1021.     | Type: ......... PC: pc...... |
  1022.     | Addr: ........  BP: ........ |
  1023.     */
  1024.  
  1025.     /* we play games to get around 128-char max for ksprintf */
  1026.     ksprintf(alertbuf,"[1][ PROCESS  \"%s\"  KILLED: |",curproc->name);
  1027.     aptr = alertbuf + strlen(alertbuf);
  1028.     ksprintf(aptr," MEMORY VIOLATION.  (PID %03d) | |",curproc->pid);
  1029.     aptr = alertbuf + strlen(alertbuf);
  1030.     ksprintf(aptr," Type: %s PC: %08lx |",vmsg,pc);
  1031.     aptr = alertbuf + strlen(alertbuf);
  1032.     ksprintf(aptr," Addr: %08lx  BP: %08lx ][ OK ]",aa,curproc->base);
  1033.     if (!_ALERT(alertbuf)) {
  1034.         /* this will call _alert again, but it will just fail again */
  1035.         ALERT("MEMORY VIOLATION: type=%s AA=%lx PC=%lx BP=%lx",
  1036.             vmsg,aa,pc,curproc->base);
  1037.     }
  1038.         
  1039.     if (curproc->pid == 0 || curproc->memflags & F_OS_SPECIAL) {
  1040.     /* the system is so thoroughly hosed that anything we try will
  1041.      * likely cause another bus error; so let's just hang up
  1042.      */
  1043.     FATAL("Operating system killed");
  1044.     }
  1045. }
  1046.  
  1047. /*
  1048.  * big_mem_dump is a biggie: for each page in the system, it
  1049.  * displays the PID of the (first) owner and the protection mode.
  1050.  * The output has three chars per page, and eight chars per line.
  1051.  * The first page of a region is marked with the mode, and the
  1052.  * rest with a space.
  1053.  *
  1054.  * Logic:
  1055.     for (mp = *core; mp; mp++) {
  1056.     for (each page of this region) {
  1057.         if (start of line) {
  1058.         output line starter;
  1059.         }
  1060.         if (start of region) {
  1061.         output mode of this page;
  1062.         determine owner;
  1063.         output owner;
  1064.         }
  1065.         else {
  1066.         output space;
  1067.         output owner;
  1068.         }
  1069.         }
  1070.     }
  1071.  */
  1072.  
  1073. void
  1074. BIG_MEM_DUMP(bigone,proc)
  1075. int bigone;
  1076. PROC *proc;
  1077. {
  1078. #ifdef DEBUG_INFO
  1079.     char linebuf[128];
  1080.     char *lp = linebuf;
  1081.     MEMREGION *mp, **mr, **map;
  1082.     PROC *p;
  1083.     ulong loc;
  1084.     short owner;
  1085.     short i;
  1086.     short first;
  1087.  
  1088.  
  1089.   if (no_mem_prot) return;
  1090.  
  1091.   for (map = core; map != 0; ((map == core) ? (map = alt) : (map = 0))) {
  1092.     FORCE("Annotated memory dump for %s",(map == core ? "core" : "alt"));
  1093.     first = 1;
  1094.     *linebuf = '\0';
  1095.     for (mp = *map; mp; mp = mp->next) {
  1096.     for (loc = mp->loc; loc < (mp->loc + mp->len); loc += EIGHT_K) {
  1097.         if (first || ((loc & 0x1ffff) == 0)) {
  1098.         if (*linebuf) FORCE(linebuf);
  1099.         ksprintf(linebuf,"\r%08lx: ",loc);
  1100.         lp = &linebuf[11];
  1101.         first = 0;
  1102.         }
  1103.         if (loc == mp->loc) {
  1104.         *lp++ = modesym[global_mode_table[loc / EIGHT_K]];
  1105.  
  1106.         for (p = proclist; p; p = p->gl_next) {
  1107.             if (p->mem) {
  1108.             mr = p->mem;
  1109.             for (i=0; i < p->num_reg; i++, mr++) {
  1110.                 if (*mr == mp) {
  1111.                 owner = p->pid;
  1112.                 goto gotowner;
  1113.                 }
  1114.             }
  1115.             }
  1116.         }
  1117.         owner = 000;
  1118. gotowner:
  1119.         ksprintf(lp,"%03d",owner);
  1120.         lp += 3;
  1121.         }
  1122.         else {
  1123.         *lp++ = ' ';
  1124.         *lp++ = '-';
  1125.         *lp++ = '-';
  1126.         *lp++ = '-';
  1127.         *lp = '\0';    /* string is always null-terminated */
  1128.         }
  1129.         }
  1130.     }
  1131.     FORCE(linebuf);
  1132.   }
  1133.  
  1134.     if (bigone) {
  1135.     long_desc tbl;
  1136.  
  1137.     /* fill in tbl with the only parts used at the top level */
  1138.     tbl.page_type.dt = proc->ctxt[CURRENT].crp.dt;
  1139.     tbl.tbl_address = proc->ctxt[CURRENT].crp.tbl_address;
  1140.     _dump_tree(tbl,0);
  1141.     }
  1142. #else
  1143.     UNUSED(proc);
  1144.     UNUSED(bigone);
  1145. #endif /* DEBUG_INFO */
  1146. }
  1147.  
  1148.  
  1149. /*
  1150.  * Can the process "p" access the "nbytes" long
  1151.  * block of memory starting at "start"?
  1152.  * If it would be a legal access, the current
  1153.  * process is given temporary access via
  1154.  * prot_temp.
  1155.  * Returns a cookie like the one prot_temp
  1156.  * returns; if the process shouldn't have
  1157.  * access to the memory, returns 1.
  1158.  *
  1159.  * BUG: should actually read p's page table to
  1160.  * determine access
  1161.  */
  1162.  
  1163. int
  1164. mem_access_for(p, start, nbytes)
  1165.     PROC *p;
  1166.     ulong start;
  1167.      long nbytes;
  1168. {
  1169.     MEMREGION **mr;
  1170.     int i;
  1171.  
  1172.     if (no_mem_prot) return -1;
  1173.     if (start >= (ulong)p && start+nbytes <= (ulong)(p+1))
  1174.         return -1;
  1175.     if (p == rootproc)
  1176.         goto win_and_mark;
  1177.  
  1178.     mr = p->mem;
  1179.     if (mr) {
  1180.         for (i = 0; i < p->num_reg; i++, mr++) {
  1181.         if (*mr) {
  1182.             if (((*mr)->loc <= start) &&
  1183.             ((*mr)->loc + (*mr)->len >= start + nbytes))
  1184.                 goto win_and_mark;
  1185.         }
  1186.         }
  1187.     }
  1188.  
  1189.     return 0;    /* we don't own this memory */
  1190.  
  1191. win_and_mark:
  1192.     return prot_temp(start, nbytes, -1);
  1193. }
  1194.